package com.quest.concurrentTools;

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;

/**
 * Semaphore场景测试(限流作用)
 *
 * 以一个停车场是运作为例。为了简单起见，假设停车场只有三个车位，一开始三个车位都是空的。
 * 这时如果同时来了五辆车，看门人允许其中三辆不受阻碍的进入，然后放下车拦，剩下的车则必须在入口等待，此后来的车也都不得不在入口处等待。
 * 这时，有一辆车离开停车场，看门人得知后，打开车拦，放入一辆，如果又离开两辆，则又可以放入两辆，如此往复。
 * 这个停车系统中，每辆车就好比一个线程，看门人就好比一个信号量，看门人限制了可以活动的线程。
 * 假如里面依然是三个车位，但是看门人改变了规则，要求每次只能停两辆车，那么一开始进入两辆车，后面得等到有车离开才能有车进入，但是得保证最多停两辆车。
 * 对于Semaphore类而言，就如同一个看门人，限制了可活动的线程数。
 *
 */
public class SemaphoreTest {
    private static Semaphore semaphore = new Semaphore(4);
    private static CountDownLatch latch = new CountDownLatch(1);
    private static class ParkProcesser implements Runnable {
        private String carNum;

        public ParkProcesser(String carNum) {
            this.carNum = carNum;
        }

        @Override
        public void run() {
            try {
                //等待停车场开门
                latch.await();
                //开始抢车位
                semaphore.acquire();//获得许可（车位）
                System.out.println(carNum + "进入停车场，剩余停车位：" + semaphore.availablePermits() + ",还有" + semaphore.getQueueLength() + "辆车正在等候");
                Thread.sleep(new Random().nextInt(10) * 1000);
                semaphore.release();//离开车位，归还许可
                System.out.println(carNum+"离开停车场~");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        int carNum = 10;
        for (int i = 0; i < carNum; i++) {
            Thread t = new Thread(new ParkProcesser("浙A." + (new Random().nextInt(100))));
            t.start();
        }
        latch.countDown();
    }
}
